on_load = """
// 页面刷新时执行的操作
  window.onbeforeunload = function() {
    // 执行你的代码
    console.log("页面即将刷新");
    window.localStorage.setItem('test_onbeforeunload', '0')
  };
"""
set_load_status = "window.localStorage.setItem('test_onbeforeunload', '1')"
get_event_listeners = "getEventListeners(document);"
js_clean_elements = "window.localStorage.setItem('test_elements', '')"
get_test_elements = "window.localStorage.getItem('test_elements')"
get_test_onbeforeunload = "window.localStorage.getItem('test_onbeforeunload')"
locator_js = """
// 缓存变量
let id = 0;
var recording = false;
var moveElemnt = null;
var moveElemntLocator = null;
var rightClickMenu = false;
var copyMoveElemnt = null;
var copyParsedElement = null;
var beforeElement = null;
var beforeElementLocator = '';
var inputElement = null;
var inputElementLocator = null;
var classLocatorResult = null;
var inputAfterStepFlag = 0;

const controlWindowConfig = {
  style: {
    position: 'absolute',
    color: '#1a1a1a',
    fontFamily: 'Sans-Serif',
    left: 'calc(50% - 90px)',
    top: 0,
    padding: '2px',
    width: '90px',
    backgroundColor: '#fff',
    borderRadius: '4px',
    boxShadow: '0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04)',
    // paddingLeft: 'calc(50% - 150px)',
    zIndex: 99999999999
  },
  attr: {
    class: 'auto-control-window',
  }
};

const dragConfig = {
  style: {
    width: '20px',
    height: '20px',
    textAlign: 'center',
    display: 'inline-block',
    lineHeight: '5px',
    padding: '8px',
    cursor: 'pointer'
  },
  attr: {
    class: 'auto-contorl-drag',
  },
  objAttr: {
    // textContent: '••••••',
    innerHTML: `<svg t="1711189305611" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1079" width="20" height="20"><path d="M362.666667 298.666667c35.346084 0 64-28.653916 64-64S398.012751 170.666667 362.666667 170.666667s-64 28.653916-64 64 28.653916 64 64 64z m0 277.333333c35.346084 0 64-28.653916 64-64s-28.653916-64-64-64S298.666667 476.653916 298.666667 512s28.653916 64 64 64z m0 277.333333c35.346084 0 64-28.653916 64-64s-28.653916-64-64-64-64 28.653916-64 64S327.320583 853.333333 362.666667 853.333333z m298.666666-554.666666c35.346084 0 64-28.653916 64-64S696.679417 170.666667 661.333333 170.666667 597.333333 199.320583 597.333333 234.666667s28.653916 64 64 64z m0 277.333333c35.346084 0 64-28.653916 64-64s-28.653916-64-64-64S597.333333 476.653916 597.333333 512s28.653916 64 64 64z m0 277.333333c35.346084 0 64-28.653916 64-64s-28.653916-64-64-64-64 28.653916-64 64S625.987249 853.333333 661.333333 853.333333z" p-id="1080"></path></svg>`,
  }
}

const startPauseConfig = {
  style: {
    width: '20px',
    height: '20px',
    textAlign: 'center',
    display: 'inline-block',
    lineHeight: '5px',
    marginLeft: '10px',
    padding: '8px',
    cursor: 'pointer',
    borderRadius: '4px',
  },
  attr: {
    class: 'auto-contorl-record',
  },
  objAttr: {
    innerHTML: `<svg t="1711431979344" class="auto-contorl-icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1663" width="20" height="20"><path d="M512 960c-247.424 0-448-200.512-448-448s200.576-448 448-448c247.488 0 448 200.512 448 448s-200.512 448-448 448zM512 138.88v-0.256C297.92 138.688 138.88 306.304 138.88 512S306.304 885.12 512 885.12s373.12-167.36 373.12-373.12S717.76 138.88 512 138.88z m-66.048 554.816a26.88 26.88 0 0 1-30.336 0.832 35.456 35.456 0 0 1-15.424-29.952V321.984c0-12.416 5.888-23.872 15.424-29.952a26.88 26.88 0 0 1 30.4 0.896l238.912 171.328c8.64 6.272 13.952 17.28 13.952 29.056s-5.312 22.784-14.016 28.992l-238.912 171.392z" fill="#707070" p-id="1664"></path></svg>`
  },
}

const dingWeiConfig = {
  style: {
    width: '20px',
    height: '20px',
    textAlign: 'center',
    display: 'inline-block',
    lineHeight: '5px',
    marginLeft: '10px',
    padding: '8px',
    cursor: 'pointer',
    borderRadius: '4px',
  },
  attr: {
    class: 'auto-contorl-locator',
  },
  objAttr: {
    // textContent: '••••••',
    innerHTML: `<svg t="1711189648072" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1203" width="20" height="20"><path d="M504.448 519.552m-151.189333 0a151.189333 151.189333 0 1 0 302.378666 0 151.189333 151.189333 0 1 0-302.378666 0Z" fill="#707070" p-id="1204"></path><path d="M504.448 124.714667c-218.069333 0-394.858667 176.768-394.858667 394.837333s176.789333 394.858667 394.858667 394.858667 394.837333-176.789333 394.837333-394.858667S722.517333 124.714667 504.448 124.714667z m0 64c182.72 0 330.837333 148.117333 330.837333 330.837333s-148.117333 330.858667-330.837333 330.858667S173.589333 702.272 173.589333 519.552c0-182.72 148.138667-330.837333 330.858667-330.837333z" fill="#707070" p-id="1205"></path><path d="M519.552 10.666667a32 32 0 0 1 32 32v98.922666a32 32 0 1 1-64 0V42.666667a32 32 0 0 1 32-32zM519.552 850.410667a32 32 0 0 1 32 32V981.333333a32 32 0 0 1-64 0v-98.922666a32 32 0 0 1 32-32z" fill="#707070" p-id="1206"></path><path d="M10.666667 519.552a32 32 0 0 1 32-32h98.922666a32 32 0 1 1 0 64H42.666667a32 32 0 0 1-32-32zM850.410667 519.552a32 32 0 0 1 32-32H981.333333a32 32 0 0 1 0 64h-98.922666a32 32 0 0 1-32-32z" fill="#707070" p-id="1207"></path></svg>`,
  }
}


const controlWindow = addElement(document.body, 'div', controlWindowConfig);
addElement(controlWindow, 'div', dragConfig);
addElement(controlWindow, 'div', startPauseConfig);
// addElement(controlWindow, 'div', dingWeiConfig);

// 获取所有元素
var elements = document.querySelectorAll("*");
// 遍历每个元素
for (var i = 0; i < elements.length; i++) {
  // 添加鼠标移入事件监听器
  elements[i].addEventListener("mouseover", function(event) {
    if(moveElemnt != event.target){
      moveElemnt = event.target
      moveElemntLocator = null
      const tagName = moveElemnt.tagName
      if(recording){
        if(tagName != 'svg' && tagName != 'path'){
          const className = moveElemnt.className
          if(className.includes('auto-')){
            if(className == 'auto-menu-button' | className == 'auto-contorl-button'){
              moveElemnt.style.backgroundColor = "#ebedf0";
            }else if(className == 'auto-menu-button'){

            }
          }else{
            var isChildNode = true
            var tipsText = ''
            var tipsColor = ''
            if(beforeElement){
              if(beforeElement == moveElemnt){
                tipsText = '级联定位不能选择同一个元素，请选择其他元素。'
                tipsColor = 'red'
                isChildNode = false
              }else if(!beforeElement.contains(moveElemnt)){
                tipsText = `此元素不是${beforeElementLocator}的子元素，请选择其他元素。`
                tipsColor = 'red'
                isChildNode = false
              }
            }
            if(isChildNode){
              // 解析当前操作元素定位 
              var notOnlyLocator = null
              if(tagName == 'INPUT' && !moveElemnt.disabled){
                const inputPlaceholder = moveElemnt.placeholder
                if(inputPlaceholder){
                  const placeholderResult = onlyOneElement(moveElemnt, tagName, 'attr', 'placeholder', inputPlaceholder)
                  if(placeholderResult){
                    if(placeholderResult.only){
                      moveElemntLocator = placeholderResult.locator
                    }else{
                      notOnlyLocator = placeholderResult
                    }
                  }
                }
                const inputValue = moveElemnt.value
                if(!moveElemntLocator && inputValue){
                  const valueResult = onlyOneElement(moveElemnt, tagName, 'attr', 'value', inputValue)
                  if(valueResult){
                    if(valueResult.only){
                      moveElemntLocator = valueResult.locator
                    }else{
                      if(notOnlyLocator){
                        notOnlyLocator = notOnlyLocator.num>valueResult.num?valueResult:notOnlyLocator
                      }else{
                        notOnlyLocator = valueResult
                      }
                    }
                  }
                }
              }

              // 尝试根据class定位元素
              const className = moveElemnt.className
              if(!moveElemntLocator && className){
                const classResult = byClassLocator(moveElemnt, className)
                classLocatorResult = null
                if(classResult){
                  const spaceNum = className.split(' ').length - 1
                  if(spaceNum < 2){
                    // 同时包含空格和-不优先使用class定位
                    if(classResult.only){
                      moveElemntLocator = classResult.locator
                    }else{
                      if(notOnlyLocator){
                        notOnlyLocator = notOnlyLocator.num>classResult.num?classResult:notOnlyLocator
                      }else{
                        notOnlyLocator = classResult
                      }
                    }
                  }else{
                    classLocatorResult = classResult
                  }
                }
              }

              // 尝试根据id定位元素
              if(!moveElemntLocator && tagName){
                const byIdResult = byIdLocator(moveElemnt, tagName, moveElemnt.id)
                if(byIdResult){
                  if(byIdResult.only){
                    moveElemntLocator = byIdResult.locator
                  }else{
                    if(notOnlyLocator){
                      notOnlyLocator = notOnlyLocator.num>byIdResult.num?byIdResult:notOnlyLocator
                    }else{
                      notOnlyLocator = byIdResult
                    }
                  }
                }
              }

              // 尝试根据text定位元素
              var text = moveElemnt.innerText
              if(!moveElemntLocator){
                if(text){
                  if(text.includes('\\n')){
                    text = text.split('\\n')[0]
                  }
                  const byTextResult = byTextLocator(moveElemnt, tagName, text)
                  if(byTextResult){
                    if(byTextResult.only){
                      moveElemntLocator = byTextResult.locator
                    }else{
                      if(notOnlyLocator){
                        notOnlyLocator = notOnlyLocator.num>byTextResult.num?byTextResult:notOnlyLocator
                      }else{
                        notOnlyLocator = byTextResult
                      }
                    }
                  }
                }
              }

              // 如果class中包含空格和横杠则优先级放到Text定位之后
              if(!moveElemntLocator && classLocatorResult){
                if(classLocatorResult.only){
                  moveElemntLocator = classLocatorResult.locator
                }else{

                  if(notOnlyLocator){
                    notOnlyLocator = notOnlyLocator.num>classLocatorResult.num?classLocatorResult:notOnlyLocator
                  }else{
                    notOnlyLocator = classLocatorResult
                  }
                }
              }

              // 根据tagName定位  && !beforeElement
              if(!moveElemntLocator){
                const byTagNameResult = byTagNameLocator(moveElemnt)
                if(byTagNameResult){
                  if(byTagNameResult.only){
                    moveElemntLocator = byTagNameResult.locator
                  }else{
                    if(notOnlyLocator){
                      notOnlyLocator = notOnlyLocator.num>byTagNameResult.num?byTagNameResult:notOnlyLocator
                    }else{
                      notOnlyLocator = byTagNameResult
                    }
                  }
                }
              }

              // 不存在唯一定位方式，则取指定下标元素
              if(!moveElemntLocator && notOnlyLocator){
                moveElemntLocator = notOnlyLocator.locator
              }

              var tipsColor = '#000000'
              if(!moveElemntLocator){
                tipsText = '没有匹配到合适的定位语句，请手动定位元素。'
                tipsColor = 'red'
              }else{
                var verifyXpath = objLocatorToXpath(moveElemntLocator)
                const node = findNodeByXpath(verifyXpath)
                if(moveElemnt != node){
                  for(var i = 0; i < 5; i ++){
                    verifyXpath = verifyXpath + '/..'
                    const node = findNodeByXpath(verifyXpath)
                    if(moveElemnt == node){
                      moveElemntLocator = {by: 'xpath', locator: verifyXpath}
                    }
                  }
                }
                tipsText = `${moveElemntLocator.by}=>${moveElemntLocator.locator}`
              }
            }

            moveElemnt.style.setProperty('background-color', 'pink', 'important');
            var rightClickMenuConfig = {
              style: {
                position: 'absolute',
                color: tipsColor,
                fontFamily: 'Sans-Serif',
                backgroundColor: '#fff',
                borderRadius: '4px',
                fontSize: '15px',
                fontWeight: 600,
                boxShadow: '0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04)',
                padding: '5px 10px',
                zIndex: 9999999999
              },
              attr: {
                class: 'auto-menu'
              },
              objAttr: {
                textContent: tipsText
              }
            }

            // 根据鼠标所在元素计算菜单出现位置
            var rect = moveElemnt.getBoundingClientRect();
            rightClickMenuConfig.style.left = rect.left + 'px';
            rightClickMenuConfig.style.top = rect.bottom + 10 + 'px';
            addElement(document.body, 'div', rightClickMenuConfig) // 添加菜单
          }
        }
      }
    }
  });

  // 添加鼠标移出事件监听器
  elements[i].addEventListener("mouseout", function(event) {
    const tagName = event.target.tagName
    if(tagName != 'svg' && tagName != 'path'){
      const className = event.target.className
      if(className.includes('auto-')){
        // 将鼠标离开的元素背景还原
        if(className == 'auto-menu' | className == 'auto-menu-tips' | className == 'auto-menu-button' | className == 'auto-contorl-button'){
          event.target.style.backgroundColor = "#fff";
        }
      }else{
          event.target.style.backgroundColor = "";
          var menu = document.querySelector('.auto-menu'); // 获取菜单元素
          if(menu){
            menu.remove();
          }

      }
    }
  });
}

// 添加右键菜单
document.addEventListener('contextmenu', function(event) {
  event.preventDefault(); // 阻止默认的右键菜单弹出
  if(!moveElemntLocator  && !beforeElement){
    return
  }
  if(!beforeElement){
    const xpath = objLocatorToXpath(moveElemntLocator)
    copyMoveElemnt = findNodeByXpath(xpath)
    copyParsedElement = xpath
  }
  // copyMoveElemnt.style.setProperty('background-color', '#409EFF', 'important');
  copyMoveElemnt.setAttribute("style", "border: 2px solid pink !important;");
  var contextMenu = document.querySelector('.auto-menu-right'); // 获取菜单元素
  if(contextMenu){
    contextMenu.remove();
  }
  // 创建菜单元素
  var rightClickMenuConfig = {
    style: {
      position: 'absolute',
      color: '#1a1a1a',
      fontFamily: 'Sans-Serif',
      backgroundColor: '#fff',
      borderRadius: '4px',
      boxShadow: '0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04)',
      padding: '10px 0',
      zIndex: 999999999999
    },
    attr: {
      class: 'auto-menu-right'
    },
    objAttr: {}
  }

  // 根据右击位置计算菜单出现位置
  var pageWidth = document.documentElement.clientWidth;
  var pageHeight = document.documentElement.clientHeight;
  const mouseClickX = event.clientX;
  const mouseClickY = event.clientY;
  const subWidth = pageWidth - mouseClickX;
  const subHeight = pageHeight - mouseClickY;
  // 设置菜单宽度位置
  if(subWidth < 150){
    rightClickMenuConfig.style.right = (subWidth + 17) + 'px'
  }else{
    rightClickMenuConfig.style.left = mouseClickX + 'px';
  }
  // 设置菜单高度位置
  if(subHeight < 200){
    rightClickMenuConfig.style.bottom = subHeight  + 'px'
  }else{
    rightClickMenuConfig.style.top = mouseClickY + 'px';
  }
  const menu = addElement(document.body, 'div', rightClickMenuConfig) // 添加菜单
  // 添加提示容器
  var multipleTipsConfig = {
    style: {
      padding: '10px',
      fontSize: '14px',
      color: 'red',
      marginBottom: '20px',
      borderBottom: '1px solid rgb(220, 223, 230)',
    },
    attr: {
      class: 'auto-menu-tips'
    },
    objAttr: {
      textContent: copyParsedElement
    }
  }
  if(beforeElementLocator){
    multipleTipsConfig.objAttr.textContent = beforeElementLocator
  }

  // 获取上一级元素按钮配置
  const parentNodeConfig = {
    style: {
      padding: '10px',
      fontSize: '14px',
      cursor: 'pointer',
    },
    attr: {
      class: 'auto-menu-button'
    },
    objAttr: {
      textContent: '获取上一级元素'
    },
  }
  // 级联定位按钮配置
  const cascadeConfig = {
    style: {
      padding: '10px',
      fontSize: '14px',
      cursor: 'pointer',
    },
    attr: {
      class: 'auto-menu-button'
    },
    objAttr: {
      textContent: '级联定位'
    },
  }
  // 取消级联定位按钮配置
  const rightMenuFooterConfig = {
    style: {
      textAlign: 'right',
      marginTop: '20px',
      borderTop: '1px solid rgb(220, 223, 230)',
    },
    attr: {
      class: 'auto-menu-footer'
    },
    objAttr: {},
  };
  const cancelCascadeConfig = {
    style: {
      padding: '10px',
      fontSize: '14px',
      cursor: 'pointer',
    },
    attr: {
      class: 'auto-menu-button'
    },
    objAttr: {
      textContent: '取消级联定位'
    },
  }
  const cancelButtonConfig = {
    style: {
      width: '60px',
      lineHeight: '25px',
      display: 'inline-block',
      marginRight: '10px',
      borderRadius: '4px',
      border: '1px solid rgb(220, 223, 230)',
      cursor: 'pointer',
      marginTop: '10px',
      textAlign: 'center',
    },
    attr: {
      class: 'auto-menu-button',
    },
    objAttr: {
      textContent: '取消'
    }
  }

  const confirmButtonConfig = {
    style: {
      width: '100px',
      lineHeight: '25px',
      display: 'inline-block',
      marginRight: '10px',
      borderRadius: '4px',
      border: '1px solid rgb(220, 223, 230)',
      backgroundColor: '#409EFF',
      cursor: 'pointer',
      marginTop: '10px',
      textAlign: 'center',
    },
    attr: {
      class: 'auto-menu-dialog-confirm',
    },
    objAttr: {
      textContent: '获取元素定位'
    }
  }
  addElement(menu, 'div', multipleTipsConfig)
  addElement(menu, 'div', parentNodeConfig)
  if(beforeElement){
    addElement(menu, 'div', cancelCascadeConfig)
  }else{
    addElement(menu, 'div', cascadeConfig)
  }
  const footer = addElement(menu, 'div', rightMenuFooterConfig);
  addElement(footer, 'div', cancelButtonConfig);
  addElement(footer, 'div', confirmButtonConfig);
  rightClickMenu = true
});


// -----------------------------------------------------------------------------------------------------------------------------
// 根据className获取元素定位
function byClassLocator(target, className) {
  const classXpath = `${isMultipleLocator()}//*[@class="${className}"]`
  var classXpathResult = document.evaluate(classXpath, document);
  const classResultList = XMatchIsOnly(target, classXpathResult)
  if(classResultList[0]){
    // return {only: true, locator: isMultipleToXpath({by: 'class', locator: className}), num: 1}
    return {only: true, locator: beforeElement | className.includes(' ')?{by: 'xpath', locator: classXpath}:{by: 'class_name', locator: className}}
  }else if(classResultList[1] > 0){
    return {only: false, locator: {by: 'xpath', locator: `(${classXpath})[${classResultList[2]}]`}, num: classResultList[1]}
  }else{
    return null
  }
};

// 根据Id获取元素定位
function byIdLocator(target, tagName, id) {
  // 根据xpath匹配所有元素  null, XPathResult.ANY_TYPE, null
  const idXpath = `${isMultipleLocator()}//*[@id="${id}"]`
  var idXpathResult = document.evaluate(idXpath, document);
  const idResultList = XMatchIsOnly(target, idXpathResult)
  if(idResultList[0]){
    return {only: true, locator: isMultipleToXpath({by: 'id', locator: id}), num: 1}
  }else if(idResultList[1] > 0){
    return {only: false, locator: {by: 'xpath', locator: `(${idXpath})[${idResultList[2]}]`}, num: idResultList[1]}
  }else{
    return null
  }
};

// 根据元素Text获取元素定位
function byTextLocator(target, tagName, text) {
  var elementNum = 9999
  var leastWayXpath = null
  const multipleXpath = isMultipleLocator()

  const textXpath = `${multipleXpath}//*[text()='${text}']`
  const textXpathResult = document.evaluate(textXpath, document);
  const textResultList = XMatchIsOnly(target, textXpathResult)
  if (textResultList[0]){
    return {only: true, locator: beforeElement?{by: 'xpath', locator: textXpath}:{by: 'get_by_text', locator: text}}
  }
  // else if(textResultList[1] > 0){
  //   if(textResultList[1] < elementNum){
  //     elementNum = textResultList[1]
  //     leastWayXpath = `(${textXpath})[${textResultList[2]}]`
  //   }
  // }

  const tnXpath = `${multipleXpath}//${tagName}[text()='${text}']`
  const tagNameXpathResult = document.evaluate(tnXpath, document);
  const textTagResultList = XMatchIsOnly(target, tagNameXpathResult)
  if (textTagResultList[0]){
    return {only: true, locator: {by: 'xpath', locator: tnXpath}}
    // return {only: true, locator: beforeElement?{by: 'xpath', locator: textXpath}:{by: 'text', locator: text}}
  }else if(textTagResultList[1] > 0){
    if(textTagResultList[1] < elementNum){
      elementNum = textTagResultList[1]
      leastWayXpath = `(${tnXpath})[${textTagResultList[2]}]`
    }
  }

  var containsXpath = `${multipleXpath}//*[contains(text(), '${text}')]`
  var containsXpathResult = document.evaluate(containsXpath, document);
  const containsResultList = XMatchIsOnly(target, containsXpathResult)
  if (containsResultList[0]){
    return {only: true, locator: isMultipleToXpath({by: 'contains', locator: text})}
  }
  // else if(containsResultList[1] > 0){
  //   if(containsResultList[1] < elementNum){
  //     elementNum = containsResultList[1]
  //     leastWayXpath = `(${containsXpath})[${containsResultList[2]}]`
  //   }
  // }
  const tcXpath = `${multipleXpath}//${tagName}[contains(text(), '${text}')]`
  var tagNameContainsXpathResult = document.evaluate(tcXpath, document);
  const tagNameContainsResultList = XMatchIsOnly(target, tagNameContainsXpathResult)
  if (tagNameContainsResultList[0]){
    return {only: true, locator: {by: 'xpath', locator: tcXpath}}
  }else if(tagNameContainsResultList[1] > 0){
    if(tagNameContainsResultList[1] < elementNum){
      elementNum = tagNameContainsResultList[1]
      leastWayXpath = `(${tcXpath})[${tagNameContainsResultList[2]}]`
    }
  }

  if(leastWayXpath){
    return {only: false, locator: {by: 'xpath', locator: leastWayXpath}, num: elementNum}
  }
};

// 根据tabName定位元素
function byTagNameLocator(target) {
  const tagName = target.tagName;
  var xpath = `${isMultipleLocator()}//${tagName}`;
  var tagNameXpathResult = document.evaluate(xpath, document);
  const matchElementResult = XMatchIsOnly(target, tagNameXpathResult);
  if(matchElementResult[0]){
    return {only: true, locator: isMultipleToXpath({by: 'tagName', locator: tagName}), num: 1};
  }else if(matchElementResult[1] > 0){
    // var pNode = target.parentNode;
    // xpath = pNode?`/${pNode.tagName}${xpath}`:xpath;
    // var flag = 0;
    // while(pNode && flag < 5){
    //   pNode = pNode.parentNode;
    //   xpath = pNode?`/${pNode.tagName}${xpath}`:xpath;
    //   flag += 1;
    // }
    // xpath = `/${xpath}`;
    const evaluateResult = document.evaluate(xpath, document);
    const upwardMatch = XMatchIsOnly(target, evaluateResult);
    if(upwardMatch[0]){
      return {only: true, locator: {by: 'xpath', locator: xpath}, num: 1};
    }else{
      return {only: false, locator: {by: 'xpath', locator: `(${xpath})[${upwardMatch[2]}]`}, num: upwardMatch[1]};
    }
  }
}

// 判断Xpath定位是否唯一
function onlyOneElement(target, tagName, attr, by, locator) {
  if(attr == 'attr'){
    const xpath = `${isMultipleLocator()}//${tagName}[@${by}='${locator}']`
    const xpathResult = document.evaluate(xpath, document);
    const attrXpathResultList = XMatchIsOnly(target, xpathResult)
    if(attrXpathResultList[0]){
      by = by=='placeholder'?'get_by_placeholder':by
      return {only: true, locator: beforeElement?{by: 'xpath', locator: xpath}:{by: by, locator: locator}}
      // return {only: true, locator: isMultipleToXpath({by: by, locator: locator}), num: 1}
    }else if(attrXpathResultList[1] > 0){
      return {only: false, locator: {by: 'xpath', locator: `(${xpath})[${attrXpathResultList[2]}]`}, num: attrXpathResultList[1]}
    }
  }
};

// 级联定位时，获取父级元素定位
function isMultipleLocator(){
  if(beforeElement){
    const pXpath = beforeElementLocator
    return pXpath
  }else{
    return ''
  }
};

//级联定位定位抓换
function isMultipleToXpath(locatorObj){
  if(beforeElement){
    const pXpath = objLocatorToXpath(locatorObj)
    return {by: 'xpath', locator: pXpath}
  }else{
    return locatorObj
  }
};


// 根据Xpath定位是否唯一
function XMatchIsOnly(target, xpathResult) {
  // 遍历结果
  var nodes = [];
  var node = xpathResult.iterateNext();
  var only = false
  var index = 1
  var targetIndex = 1
  var mouseoverNode = null
  while (node) {
    nodes.push(node);
    node = xpathResult.iterateNext();
    index += 1
    if(target == node){
      targetIndex = index
      mouseoverNode = node
    }
  }
  if (nodes.length == 1){
    only = true
  }
  return [only, nodes.length, targetIndex, mouseoverNode]
};

// 
function findNodeByXpath(xpath){
  // 遍历结果
  const xpathResult = document.evaluate(xpath, document);
  var node = xpathResult.iterateNext();
  return node
};

// 将原始定位转为xpath定位
function objLocatorToXpath(locatorObj){
  if(locatorObj){
    const by = locatorObj.by
    const locator = locatorObj.locator
    if(by == 'class_name'){
      return `//*[@class='${locator}']`
    }else if(by == 'id'){
      return `//*[@id='${locator}']`
    }else if(by == 'get_by_text'){
      return `//*[text()='${locator}']`
    }else if(by == 'contains'){
      return `//*[contains(text(), '${locator}')]`
    }else if(by == 'value'){
      return `//input[@value='${locator}']`
    }else if(by == 'get_by_placeholder'){
      return `//input[@placeholder='${locator}']`
    }else{
      return locator
    }
  }
};

// -----------------------------------------------------------------------------------------------------------------------------

// 添加容器指定容器
function addElement(parentNode, tagName, childNodeConfig){
  var newElement = document.createElement(tagName);

  // 设置元素样式
  const styleConfig = childNodeConfig.style
  Object.keys(styleConfig).forEach(key => {
    newElement.style[key] = styleConfig[key]
  });

  // 设置元素属性值
  const attrConfig = childNodeConfig.attr
  if(attrConfig){
    Object.keys(attrConfig).forEach(key => {
      newElement.setAttribute(key, attrConfig[key])
    });
  }

  // 设置对象key值
  const objAttrConfig = childNodeConfig.objAttr
  if(objAttrConfig){
    Object.keys(objAttrConfig).forEach(key => {
      newElement[key] = objAttrConfig[key]
    });
  }
  parentNode.appendChild(newElement);
  return newElement
};

// -------------------------------------------------------------------------------------------------
// 样式批量设置
function saveLocator(locatorObj) {
  locatorObj.id = id++
  const pathList = window.location.href.split('/');
  var path = ''
  for(var i = 3; i < pathList.length; i ++){
    if(pathList[i] && !pathList[i].includes(':') && !pathList[i].includes('#') && !pathList[i].includes('=')){
      path += `/${pathList[i]}`
    }
  }
  locatorObj.page = path;
  if(inputAfterStepFlag > 0){
    setTimeout(function() {
      window.localStorage.setItem('test_elements', JSON.stringify(locatorObj))
    }, 500);
  }else{
    window.localStorage.setItem('test_elements', JSON.stringify(locatorObj))
  }
}

// -------------------------------------------------------------------------------------------------
// 定义事件处理函数
function onBlurHandler() {
  // 在这里编写事件处理逻辑
  inputElementLocator.action = 'fill'
  inputElementLocator.value = inputElement.value
  inputElementLocator.id = id++
  inputElementLocator.path = '/test'
  // saveLocator(inputElementLocator)
  // 移除事件监听器
  window.localStorage.setItem('test_elements', JSON.stringify(inputElementLocator))
  inputElement.removeEventListener("blur", onBlurHandler);
}

// 添加点击事件：点击菜单中的《》获取元素
document.addEventListener('click', function(event) {
  inputAfterStepFlag -= 1
  const eventTarget = event.target
  const tagName = eventTarget.tagName
  if(tagName == 'path'){
    const controlElementButton = eventTarget.parentNode.parentNode.className
    if(controlElementButton == 'auto-contorl-record'){
      recording = !recording
      eventTarget.style.fill = recording?'#FF3232':'#707070';
    }
    return
  }else if(tagName == 'svg'){
    if(eventTarget.parentNode.className == 'auto-contorl-record'){
      recording = !recording
      const el = eventTarget.children[0]; 
      el.setAttribute("style", `fill: ${recording?'#FF3232':'#707070'};`);
    }
    return
  }else if(tagName == 'INPUT'){
    // 添加事件监听器
    if(moveElemntLocator){
      inputElement = eventTarget
      moveElemntLocator.action = 'click'
      inputElementLocator = moveElemntLocator
      saveLocator(inputElementLocator)
      inputAfterStepFlag = 2
      inputElement.addEventListener("blur", onBlurHandler);
    }
    return
  }else if(rightClickMenu){
    if(eventTarget.className == 'auto-menu-button'){
      const buttonText = eventTarget.innerText
      if(buttonText == '获取上一级元素'){
        if(copyMoveElemnt.tagName != 'BODY'){
          copyParsedElement = copyParsedElement + '/..'
          // copyMoveElemnt.style.backgroundColor = "";
          copyMoveElemnt.style.border = ''
          copyMoveElemnt = copyMoveElemnt.parentNode
          // const node = findNodeByXpath(xpath)
          if(beforeElement){
            beforeElement = copyMoveElemnt
            beforeElementLocator = copyParsedElement
          }
          copyMoveElemnt.setAttribute("style", "border: 2px solid pink !important;");
          // node.setAttribute("style", 'background: pink !important');
          document.querySelector('.auto-menu-tips').textContent = copyParsedElement
        }else{
          var tips = document.querySelector('.auto-menu-tips'); // 获取菜单元素
          const text = tips.innerText
          if(!text.includes('已定位到根节点')){
            tips.innerHTML = text + '<span class="auto-menu-tips-error" style="color: red">已定位到根节点</span>'
          }
        }
      }else{
        if(buttonText == '级联定位'){
          beforeElement = copyMoveElemnt
          beforeElementLocator = copyParsedElement
        }else if(buttonText == '取消级联定位'){
          copyMoveElemnt.style.border = ''
          copyMoveElemnt = null
          copyParsedElement = null
          beforeElement = null
          beforeElementLocator = ''
        }else if(buttonText == '取消'){
          copyMoveElemnt.style.border = ''
          copyMoveElemnt = null
          copyParsedElement = null
          beforeElement = null
          beforeElementLocator = ''
        }else if(buttonText == '获取元素'){
          copyParsedElement.action = 'locator';
          saveLocator(copyParsedElement)
        }
        const rightMenu = document.querySelector('.auto-menu-right')
        if(rightMenu){
          rightMenu.remove()
        }
        rightClickMenu = false
      }
    }
  }
  if(moveElemntLocator){
    moveElemntLocator.action = 'click';
    saveLocator(moveElemntLocator)
  }
}, true);
"""